#include "event.hh"

namespace wb
{
event::event(bool is_set) noexcept
    : event_state_((is_set) ? static_cast<void*>(this) : nullptr)
{
}

bool event::awaiter::await_suspend(std::coroutine_handle<> h) noexcept
{
    const void* const state = &owner_event;
    awaiting_coroutine = h;
    void* old_ptr = owner_event.event_state_.load(std::memory_order::acquire);
    do
    {
        // Resume immediately if the state has already been set.
        if (old_ptr == state)
        {
            return false;
        }
        next = static_cast<awaiter*>(old_ptr);
    } while (owner_event.event_state_.compare_exchange_weak(
        old_ptr, this, std::memory_order::release, std::memory_order::acquire));

    return true;
}

void event::set(resume_order_policy p) noexcept
{
    void* old_ptr = event_state_.exchange(this, std::memory_order::acq_rel);
    if (old_ptr != this)
    {
        if (p == resume_order_policy::fifo)
        {
            old_ptr = reverse(static_cast<awaiter*>(old_ptr));
        }

        auto* awaiters = static_cast<awaiter*>(old_ptr);
        while (awaiters != nullptr)
        {
            awaiters->awaiting_coroutine.resume();
            awaiters = awaiters->next;
        }
    }
}

void event::reset() noexcept
{
    void* old_ptr = this;
    event_state_.compare_exchange_strong(old_ptr,
                                         nullptr,
                                         std::memory_order::acquire);
}

event::awaiter* event::reverse(awaiter* head) noexcept
{
    if (head == nullptr || head->next == nullptr)
    {
        return head;
    }

    // prev to be the new head
    awaiter* prev = nullptr;
    awaiter* next = nullptr;
    // Reversing linked list
    while (head != nullptr)
    {
        next = head->next;
        head->next = prev;
        prev = head;
        head = next;
    }
    return prev;
}
}  // namespace wb